package com.studerb.view.headers;

import static com.studerb.util.Constants.EVENT_SERVICE_NAME;

import java.util.Date;
import java.util.List;

import javax.swing.table.AbstractTableModel;

import org.apache.log4j.Logger;
import org.bushe.swing.event.annotation.AnnotationProcessor;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.springframework.beans.factory.annotation.Autowired;

import com.studerb.events.HeaderEvent;
import com.studerb.events.NewsGroupEvent;
import com.studerb.model.Header;
import com.studerb.model.NewsGroup;
import com.studerb.model.Post;
import com.studerb.service.interfaces.IHeaderService;
import com.studerb.service.interfaces.INewsGroupService;

public class HeadersTableModel extends AbstractTableModel {
	private static final Logger logger = Logger.getLogger(HeadersTableModel.class);
	private final static Class[] columnClasses = new Class[] { String.class, String.class, Integer.class, Date.class, Boolean.class };
	private final static String[] columnNames = new String[] { "Subject", "Author", "Bytes", "Posted", "Downloaded" };
	private final static boolean[] isEditable = new boolean[] { false, false, false, false, false };
	@Autowired protected INewsGroupService newsGroupService;

	@Autowired protected IHeaderService headerService;
	private List<Post> posts;
	protected NewsGroup newsGroup;

	HeadersTableModel(NewsGroup newsGroup) {
		super();
		this.newsGroup = newsGroup;
	}

	@Override public Class getColumnClass(int columnIndex) {
		return columnClasses[columnIndex];
	}

	@Override public int getColumnCount() {
		return columnNames.length;
	}

	@Override public String getColumnName(int column) {
		return columnNames[column];
	}

	public Post getPost(int index) {
		return this.posts.get(index);
	}

	@Override public int getRowCount() {
		return this.posts.size();
	}

	@Override public Object getValueAt(int rowIndex, int columnIndex) {
		Post post = this.posts.get(rowIndex);
		switch (columnIndex) {
		case 0:
			return post.getSubject();
		case 1:
			return post.getAuthor();
		case 2:
			return post.getByteCount();
		case 3:
			return post.getDatePosted().getTime();
		case 4:
			return post.isArticleDownloaded();
		default:
			throw new IllegalArgumentException("Should never have header column index of: " + columnIndex);
		}
	}

	private void headerUpdated(Header header) {
		int index = this.posts.indexOf(header);
		if (index == -1) {
			throw new RuntimeException("Updated header not in model list: " + header.toString());
		}
		fireTableRowsUpdated(index, index);
	}

	public void init() {
		posts = headerService.getPosts(newsGroup, null, null);
		logger.debug("Got " + posts.size() + " headers for group: " + newsGroup.getGroupName());
		AnnotationProcessor.process(this);
	}

	@Override public boolean isCellEditable(int rowIndex, int columnIndex) {
		return isEditable[columnIndex];
	}

	@EventSubscriber(eventServiceName = EVENT_SERVICE_NAME) public void onHeaderEvent(HeaderEvent evt) {
		HeaderEvent.EventType eventType = evt.getType();
		logger.debug("Caught header event: " + eventType);
		switch (eventType) {
		case UPDATED:
			headerUpdated(evt.getHeader());
		default:
			break;
		}
	}

	@EventSubscriber(eventServiceName = EVENT_SERVICE_NAME) public void onNewsGroupEvent(NewsGroupEvent evt) {
		NewsGroupEvent.EventType eventType = evt.getType();
		switch (eventType) {
		case HEADERS:
			if (this.newsGroup.equals(evt.getNewsGroup())) {
				this.posts = headerService.getPosts(this.newsGroup, null, null);
				fireTableDataChanged();
			}
		case ALL_REFRESHED:
		case UPDATED:
		default:
			break;
		}
	}

	public enum Column {
		SUBJECT, AUTHOR, BYTES, DATE_POSTED, DOWNLOADED
	}
}